AddCSLuaFile("shared.lua")
include('shared.lua')

local BALL_HOLD_HEIGHT = 10
local BALL_KICK_HEIGHT = 40
local BALL_RADIUS = 16
local DISTANCE_BETWEEN_PLAYER_AND_BALL = 55

local BallModel = "models/roller_spikes.mdl"
local BallOwner = nil
ENT.Free = true

function ENT:Initialize()	
	self.Entity:SetModel(BallModel)
	self.Entity:PhysicsInit(SOLID_VPHYSICS)
	self.Entity:SetMoveType(MOVETYPE_VPHYSICS)
	self.Entity:SetSolid(SOLID_VPHYSICS)
	self.Entity:PhysicsInitSphere(BALL_RADIUS, "metal_bouncy")
	local phys = self.Entity:GetPhysicsObject()
	if (phys:IsValid()) then
		phys:Wake()
	end
end

function ENT:OnTakeDamage(dmginfo)
	self.Entity:TakePhysicsDamage(dmginfo)
end

function ENT:Use(activator, caller)

end

function ENT:Think()
	if not self:IsFree() then		
		self:SetInFrontOfBallOwner(BALL_HOLD_HEIGHT)
		if self.ShouldBeKicked then
			self:Kick(self.KickStrength)
		end
	end
end

function ENT:StartTouch(ent)
	
end

function ENT:Spawn()
	self.BaseClass:Spawn()
	self:SetFree()
end

function ENT:Touch(ent)	
	if ent:IsValid() and self:IsFree() and ent:IsPlayer()  then		
		self:SetBallOwner(ent)
	end
end

function ENT:PhysicsCollide(data, physobj)
	if self:HasBallOwner() then	
		if data.HitEntity:GetName() == "dangerous_goal_red" and self:GetBallOwner():Team() == DsTeam.Blue then
			gamemode.Call("Goal", DsTeam.Blue)
			return
		elseif data.HitEntity:GetName() == "dangerous_goal_blue" and self:GetBallOwner():Team() == DsTeam.Red then
			gamemode.Call("Goal", DsTeam.Red)
			return
		end
	end
	if (data.Speed > 80 && data.DeltaTime > 0.2) then
		self.Entity:EmitSound("physics/glass/glass_sheet_step1.wav")
	end
	local oldVelocity = physobj:GetVelocity()
	local newVelocity = oldVelocity * 0.9
	physobj:SetVelocity(newVelocity)	
end

function ENT:SetNonSolidToPlayers()
	self.Entity:SetSolid(SOLID_NONE)
end

function ENT:SetSolidToPlayers()	
	self.Entity:SetSolid(SOLID_VPHYSICS)
end

function ENT:SetInFrontOfBallOwner(heightAddition)
	local ballOwnerEyeAngles = self:GetBallOwner():EyeAngles()
	local ballOwnerPosition = self:GetBallOwner():GetPos()
	
	local angle = math.rad(ballOwnerEyeAngles.y)
	local cos = math.cos(angle)
	local sin = math.sin(angle)
	local targetPosition = Vector(0, 0, 0)
	targetPosition[1] = ballOwnerPosition[1] + cos * DISTANCE_BETWEEN_PLAYER_AND_BALL
	targetPosition[2] = ballOwnerPosition[2] + sin * DISTANCE_BETWEEN_PLAYER_AND_BALL
	targetPosition[3] = ballOwnerPosition[3] + heightAddition
	self:GetPhysicsObject():SetPos(targetPosition)
end

function ENT:Kick(strength)
	if self:IsFree() then
		return
	end	
	if self:IsInterferenceForKick() then
		self.ShouldBeKicked = true
		self.KickStrength = strength
		return
	end	
	self.ShouldBeKicked = false
	self:SetInFrontOfBallOwner(BALL_KICK_HEIGHT)
	local ballOwnerEyeAngles = self:GetBallOwner():EyeAngles()
	local anglesVector = ballOwnerEyeAngles:Forward()
	local ballVelocity = anglesVector * strength		
	self:GetPhysicsObject():SetVelocity(ballVelocity)
	self:SetFree()
end

function ENT:HasBallOwner()
	return self:GetBallOwner() != nil
end

function ENT:GetBallOwner()
	return BallOwner
end

function ENT:SetBallOwner(owner)
	BallOwner = owner
	self:SetNonFree()
	self:SetInFrontOfBallOwner(BALL_HOLD_HEIGHT)
	owner:BallReceiving()
end

function ENT:RemoveBallOwner()
	BallOwner = nil
end

function ENT:SetFree()
	self.Free = true
	self:SetSolidToPlayers()
end

function ENT:SetNonFree()
	self.Free = false
	self:SetNonSolidToPlayers()
end

function ENT:IsFree()
	return self.Free
end

function ENT:IsInterferenceForKick()
	local ballOwnerEyeAngles = self:GetBallOwner():EyeAngles()	
	local angle = ballOwnerEyeAngles.y
	local cos = math.cos(math.rad(angle))
	local sin = math.sin(math.rad(angle))
	
	local ballOwnerPosition = self:GetBallOwner():GetPos()
	
	local leftBottomPosition = Vector(0, 0, 0)
	leftBottomPosition[1] = ballOwnerPosition[1] - sin * BALL_RADIUS
	leftBottomPosition[2] = ballOwnerPosition[2] - cos * BALL_RADIUS
	leftBottomPosition[3] = ballOwnerPosition[3] + BALL_KICK_HEIGHT - BALL_RADIUS
	
	local startOriginAddtitions = Vector(0, 0, 0)
	startOriginAddtitions[1] = sin * BALL_RADIUS;
	startOriginAddtitions[2] = cos * BALL_RADIUS;
	startOriginAddtitions[3] = BALL_RADIUS;
	
	local testOriginAdditions = Vector(0, 0, 0)
	testOriginAdditions[1] = cos * (DISTANCE_BETWEEN_PLAYER_AND_BALL + BALL_RADIUS);
	testOriginAdditions[2] = sin * (DISTANCE_BETWEEN_PLAYER_AND_BALL + BALL_RADIUS);
	testOriginAdditions[3] = 0.0;
	
	local startPosition = Vector(0, 0, 0)
	local testPosition = Vector(0, 0, 0)
	local filteredEntities = player.GetAll()
	table.insert(filteredEntities, self.Entity)
	for x = 1, 3 do
		for y = 1, 3 do
			for z = 1, 3 do
				startPosition[1] = leftBottomPosition[1] + x * startOriginAddtitions[1];
				startPosition[2] = leftBottomPosition[2] + y * startOriginAddtitions[2];
				startPosition[3] = leftBottomPosition[3] + z * startOriginAddtitions[3];
				for j = 1, 3 do
					testPosition[j] = startPosition[j] + testOriginAdditions[j];
				end			
				
				local tracedata = {}
				tracedata.start = startPosition
				tracedata.endpos = testPosition
				tracedata.filter = filteredEntities
				tracedata.mask = MASK_SOLID
				local trace = util.TraceLine(tracedata)
				if trace.Hit then
					MsgN("hit " .. tostring(trace.Entity))
					return true
				end
			end
		end
	end
	return false
end